using Circus.CodeEditor;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
namespace Circus.CodeEditor.TextSource
{
	public class LineStyles : SortList<ILineStyle>, IList<ILineStyle>, ICollection<ILineStyle>, IEnumerable<ILineStyle>, IEnumerable
	{
		private class StyleComparer : IComparer<ILineStyle>
		{
			public virtual int Compare(ILineStyle x, ILineStyle y)
			{
				int num = x.Line - y.Line;
				if (num == 0)
				{
					num = x.Pos - y.Pos;
				}
				if (num == 0)
				{
					num = y.Priority - x.Priority;
				}
				return num;
			}
		}
		private class LineComparer : IComparer<ILineStyle>
		{
			public int Compare(ILineStyle x, ILineStyle y)
			{
				return x.Line - y.Line;
			}
		}
		private class PointComparer : IComparer<ILineStyle>
		{
			public int Compare(ILineStyle x, ILineStyle y)
			{
				int num = x.Line - y.Line;
				if (num == 0)
				{
					num = x.Pos - y.Pos;
				}
				return num;
			}
		}
		private class LineStyleComparer : IComparer<ILineStyle>
		{
			public int Compare(ILineStyle x, ILineStyle y)
			{
				int num = x.Line - y.Line;
				if (num == 0)
				{
					num = x.Pos - y.Pos;
				}
				if (num == 0)
				{
					num = x.Index - y.Index;
				}
				return num;
			}
		}
		private TextSource owner;
		protected IComparer<ILineStyle> lineComparer;
		protected IComparer<ILineStyle> pointComparer;
		protected IComparer<ILineStyle> lineStyleComparer;
		protected IComparer<ILineStyle> styleComparer;
		protected virtual ILineStyle NewLineStyle(int line, int ch, int index, int priority, Range range)
		{
			return new LineStyle(line, ch, index, priority, range);
		}
		protected virtual bool UpdatePosition(int x, int y, int deltaX, int deltaY, ILineStyle style)
		{
			bool result = true;
			Point point = new Point(Math.Max(style.Pos, 0), style.Line);
			if (SortList<ILineStyle>.UpdatePos(x, y, deltaX, deltaY, ref point, false))
			{
				style.Position = new Point((style.Pos >= 0) ? point.X : style.Pos, point.Y);
				if (style.Range != null)
				{
					style.Range.StartPoint = point;
				}
				result = true;
			}
			if (style.Range != null)
			{
				point = style.Range.EndPoint;
				if (SortList<ILineStyle>.UpdatePos(x, y, deltaX, deltaY, ref point, true))
				{
					style.Range.EndPoint = point;
					result = true;
				}
			}
			return result;
		}
		protected virtual bool PositionChanged(int x, int y, int deltaX, int deltaY, IComparer<ILineStyle> lineComparer, IComparer<ILineStyle> sortComparer)
		{
			int num = 0;
			if (lineComparer != null)
			{
				base.FindFirst(new LineStyle(y), out num, lineComparer);
			}
			bool result;
			if (num >= 0)
			{
				bool flag = false;
				for (int i = num; i < base.Count; i++)
				{
					if (this.UpdatePosition(x, y, deltaX, deltaY, base[i]))
					{
						flag = true;
					}
				}
				if (flag)
				{
					if (sortComparer != null)
					{
						base.Sort(sortComparer);
					}
					result = true;
					return result;
				}
			}
			result = false;
			return result;
		}
		protected virtual bool ShouldDelete(ILineStyle style, Rectangle rect)
		{
			Point pt = new Point(Math.Max(style.Pos, 0), style.Line);
			Point pt2 = (style.Range != null) ? style.Range.EndPoint : new Point(int.MaxValue, style.Line);
			return SortList<ILineStyle>.InsideRange(pt, rect) && SortList<ILineStyle>.InsideRange(pt2, rect, true);
		}
		protected int InternalGet(int line)
		{
			int index;
			int result;
			if (base.FindFirst(new LineStyle(line), out index, this.lineComparer))
			{
				result = base[index].Index;
			}
			else
			{
				result = -1;
			}
			return result;
		}
		protected void InternalSet(ILineStyle style)
		{
			int index;
			if (base.FindFirst(style, out index, this.pointComparer))
			{
				base.RemoveAt(index);
			}
			base.Insert(index, style);
		}
		protected void InternalSet(int line, int index)
		{
			int index2;
			if (base.FindFirst(new LineStyle(line), out index2, this.lineComparer))
			{
				base.RemoveAt(index2);
			}
			base.Insert(index2, this.NewLineStyle(line, 0, index, -1, null));
		}
		protected void InternalSet(int line, int pos, int index)
		{
			int index2;
			if (base.FindFirst(new LineStyle(line, pos, -1), out index2, this.pointComparer))
			{
				base.RemoveAt(index2);
			}
			base.Insert(index2, this.NewLineStyle(line, pos, index, -1, null));
		}
		protected void InternalClear(int index)
		{
			int num = this.FindByIndex(index);
			if (num >= 0)
			{
				base.RemoveAt(num);
			}
		}
		protected void InternalClearLine(int line)
		{
			int num = 0;
			if (base.FindLast(new LineStyle(line), out num, this.lineComparer))
			{
				for (int i = num; i >= 0; i--)
				{
					if (base[num].Line != line)
					{
						break;
					}
					base.RemoveAt(i);
				}
			}
		}
		protected int FindByLine(int line)
		{
			int num;
			int result;
			if (base.FindFirst(new LineStyle(line), out num, this.lineComparer))
			{
				result = num;
			}
			else
			{
				result = -1;
			}
			return result;
		}
		protected int FindByIndex(int index)
		{
			int result;
			for (int i = 0; i < base.Count; i++)
			{
				if (base[i].Index == index)
				{
					result = i;
					return result;
				}
			}
			result = -1;
			return result;
		}
		private void InsertLineStyle(Point position, int style, int index, int priority, Range range)
		{
			if (this.owner != null)
			{
				this.owner.BeginUpdate(UpdateReason.Other);
			}
			try
			{
				ILineStyle lineStyle = this.NewLineStyle(position.Y, position.X, style, priority, range);
				if (index < 0)
				{
					base.FindFirst(lineStyle, out index, this.styleComparer);
				}
				base.Insert(index, lineStyle);
				base.Sort(this.styleComparer);
				if (this.owner != null)
				{
					if (range != null)
					{
						this.owner.LinesChanged(range.StartPoint.Y, range.EndPoint.Y);
					}
					else
					{
						this.owner.LinesChanged(position.Y, position.Y);
					}
					this.owner.State |= NotifyState.BookMarkChanged;
				}
			}
			finally
			{
				if (this.owner != null)
				{
					this.owner.EndUpdate();
				}
			}
		}
		public LineStyles()
		{
			this.lineComparer = new LineStyles.LineComparer();
			this.pointComparer = new LineStyles.PointComparer();
			this.lineStyleComparer = new LineStyles.LineStyleComparer();
			this.styleComparer = new LineStyles.StyleComparer();
		}
		public LineStyles(TextSource owner) : this()
		{
			this.owner = owner;
		}
		public virtual void Assign(LineStyles source)
		{
			this.owner.BeginUpdate(UpdateReason.Other);
			try
			{
				base.Clear();
				foreach (ILineStyle current in source)
				{
					base.Add(this.NewLineStyle(current.Line, current.Pos, current.Index, current.Priority, current.Range));
				}
				this.owner.LinesChanged(0, int.MaxValue);
				this.owner.State |= NotifyState.BookMarkChanged;
			}
			finally
			{
				this.owner.EndUpdate();
			}
		}
		protected virtual void RemoveLineAt(int idx, int line)
		{
			if (this.owner != null)
			{
				this.owner.BeginUpdate(UpdateReason.Other);
				try
				{
					base.RemoveAt(idx);
					this.owner.State |= NotifyState.BookMarkChanged;
					this.owner.LinesChanged(line, line);
				}
				finally
				{
					this.owner.EndUpdate();
				}
			}
			else
			{
				base.RemoveAt(idx);
			}
		}
		public virtual void SetLineStyle(Point position, Range range, int priority, int style)
		{
			if (this.owner != null)
			{
				this.owner.BeginUpdate(UpdateReason.Other);
			}
			try
			{
				ILineStyle lineStyle = this.NewLineStyle(position.Y, position.X, style, priority, range);
				int index;
				if (base.FindFirst(lineStyle, out index, this.styleComparer))
				{
					base[index].Assign(lineStyle);
				}
				else
				{
					base.Insert(index, lineStyle);
				}
				if (this.owner != null)
				{
					if (range != null)
					{
						this.owner.LinesChanged(range.StartPoint.Y, range.EndPoint.Y);
					}
					else
					{
						this.owner.LinesChanged(position.Y, position.Y);
					}
					this.owner.State |= NotifyState.BookMarkChanged;
				}
			}
			finally
			{
				if (this.owner != null)
				{
					this.owner.EndUpdate();
				}
			}
		}
		public virtual int GetLineStyle(int index)
		{
			return this.InternalGet(index);
		}
		public virtual int GetLineStyles(int line, IList<ILineStyle> list)
		{
			list.Clear();
			foreach (ILineStyle current in this)
			{
				int num = (current.Range != null) ? current.Range.EndPoint.Y : current.Line;
				if (line >= current.Line && line <= num)
				{
					list.Add(current);
				}
			}
			return list.Count;
		}
		public virtual void SetLineStyle(int line, int priority, int style)
		{
			this.SetLineStyle(new Point(-1, line), null, priority, style);
		}
		public virtual void SetLineStyle(Range range, int priority, int style)
		{
			this.SetLineStyle(range.StartPoint, range, priority, style);
		}
		public virtual void SetLineStyle(Point position, int priority, int style)
		{
			this.SetLineStyle(position, null, priority, style);
		}
		public virtual void SetLineStyle(int index, int style)
		{
			this.SetLineStyle(new Point(-1, index), null, -1, style);
		}
		public virtual void RemoveLineStyle(int line)
		{
			int num = this.FindByLine(line);
			if (num >= 0)
			{
				this.RemoveLineAt(num, line);
			}
		}
		public virtual void ToggleLineStyle(int line, int style)
		{
			this.ToggleLineStyle(line, -1, style);
		}
		public virtual void ToggleLineStyle(int line, int priority, int style)
		{
			int num = this.FindByLine(line);
			bool flag = false;
			if (num >= 0)
			{
				for (int i = num; i < base.Count; i++)
				{
					ILineStyle lineStyle = base[i];
					if ((lineStyle.Range != null && lineStyle.Range.StartPoint.Y <= line && lineStyle.Range.EndPoint.Y >= line) || lineStyle.Line == line)
					{
						if (lineStyle.Line != line)
						{
							break;
						}
						num = i;
						if (lineStyle.Index == style)
						{
							flag = true;
							break;
						}
					}
				}
			}
			if (flag)
			{
				this.RemoveLineAt(num, line);
			}
			else
			{
				if (num >= 0)
				{
					num++;
				}
				this.InsertLineStyle(new Point(-1, line), style, num, priority, null);
			}
		}
		public virtual bool BlockDeleting(Rectangle rect)
		{
			bool result = false;
			int num;
			base.FindLast(new LineStyle(rect.Bottom), out num, this.lineComparer);
			if (num >= 0)
			{
				for (int i = Math.Min(num, base.Count - 1); i >= 0; i--)
				{
					ILineStyle lineStyle = base[i];
					if (lineStyle.Line < rect.Top)
					{
						break;
					}
					if (this.ShouldDelete(lineStyle, rect))
					{
						result = true;
						base.RemoveAt(i);
					}
				}
			}
			return result;
		}
		public virtual bool PositionChanged(int x, int y, int deltaX, int deltaY)
		{
			return this.PositionChanged(x, y, deltaX, deltaY, null, this.lineStyleComparer);
		}
	}
}
